package dormouse.vfs.ui;

import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;

import org.apache.commons.vfs2.FileObject;
import org.apache.commons.vfs2.FileSystemException;
import org.apache.commons.vfs2.FileType;
import org.jdesktop.application.ResourceMap;

public class IconFactory {

	public static final int SIZE_16 = 16;

	public static final int SIZE_22 = 22;

	public static final int SIZE_32 = 32;

	public static final int SIZE_48 = 48;

	public static final int SIZE_64 = 64;

	private static Map<String, String> iconNameMap = new HashMap<String, String>();

	static {

		iconNameMap.put("jpg", "mimetypes/image-x-generic.png");
		iconNameMap.put("png", "mimetypes/image-x-generic.png");
		iconNameMap.put("gif", "mimetypes/image-x-generic.png");
		iconNameMap.put("svg", "mimetypes/image-x-generic.png");
		iconNameMap.put("bmp", "mimetypes/image-x-generic.png");
		iconNameMap.put("pnm", "mimetypes/image-x-generic.png");
		iconNameMap.put("psd", "mimetypes/image-x-generic.png");

		iconNameMap.put("ra", "mimetypes/audio-x-generic.png");
		iconNameMap.put("ac3", "mimetypes/audio-x-generic.png");
		iconNameMap.put("mp3", "mimetypes/audio-x-generic.png");

		iconNameMap.put("ppt", "mimetypes/x-office-presentation.png");
		iconNameMap.put("doc", "mimetypes/x-office-document.png");
		iconNameMap.put("xls", "mimetypes/x-office-spreadsheet.png");
		iconNameMap.put("txt", "mimetypes/text-x-generic.png");

		iconNameMap.put("java", "mimetypes/text-x-script.png");
		iconNameMap.put("sh", "mimetypes/text-x-script.png");
		iconNameMap.put("pl", "mimetypes/text-x-script.png");
		iconNameMap.put("groovy", "mimetypes/text-x-script.png");
		iconNameMap.put("ruby", "mimetypes/text-x-script.png");
		iconNameMap.put("py", "mimetypes/text-x-script.png");
		iconNameMap.put("js", "mimetypes/text-x-script.png");
		iconNameMap.put("class", "mimetypes/text-x-script.png");

		iconNameMap.put("zip", "mimetypes/package-x-generic.png");
		iconNameMap.put("tar", "mimetypes/package-x-generic.png");
		iconNameMap.put("bzip", "mimetypes/package-x-generic.png");
		iconNameMap.put("gzip", "mimetypes/package-x-generic.png");
		iconNameMap.put("jar", "mimetypes/package-x-generic.png");

		iconNameMap.put("css", "mimetypes/text-html.png");
		iconNameMap.put("html", "mimetypes/text-html.png");
		iconNameMap.put("pdf", "mimetypes/text-x-generic.png");
		iconNameMap.put("xml", "mimetypes/text-html.png");
		iconNameMap.put("mpg", "mimetypes/video-x-generic.png");
		iconNameMap.put("mov", "mimetypes/video-x-generic.png");
		iconNameMap.put("rtf", "mimetypes/text-x-generic.png");

		iconNameMap.put("dir", "places/folder.png");

	}

	/**
	 * This method creates an icon and scales the image to the appropriate size.
	 * 
	 * @param file
	 * @param iconSize
	 * @return
	 * @throws IOException
	 */
	public static Icon getInstance(String file, int iconSize)
			throws IOException {
		ImageIcon icon = new ImageIcon();
		URL url = IconFactory.class.getResource(file);
		if (url == null) {
			throw new IOException("The file cannot be found. File: " + file);
		}
		BufferedImage img = ImageIO.read(url);
		if (img.getWidth() != iconSize) {

			AffineTransform tx = new AffineTransform();
			tx.scale(iconSize, iconSize);

			AffineTransformOp op = new AffineTransformOp(tx,
					AffineTransformOp.TYPE_BILINEAR);
			img = op.filter(img, null);
			tx = null;
			op = null;

		}

		icon.setImage(img);

		return icon;
	}

	/**
	 * This method gets the icon referred to in the 'file' parameter.
	 * 
	 * @param file
	 * @return
	 */
	public static Icon getInstance(String file) {
		ImageIcon icon = null;
		URL url = IconFactory.class.getResource(file);
		if (url == null) {
			throw new RuntimeException("Unable to load icon for: " + file);
		}
		icon = new ImageIcon(url);
		if (icon == null) {
			throw new RuntimeException("Unable to load icon for: " + file);
		}
		return icon;
	}

	/**
	 * This method gets an instance of an icon based on the file object being
	 * passed to the factory.
	 * 
	 * @param file
	 * @param sizeConstant
	 * @return
	 */
	public static Icon getInstance(FileObject file, int sizeConstant) {

		String dir = getDir(sizeConstant);

		ImageIcon icon = null;

		try {
			String ext = null;
			if (file.getType() == FileType.FILE) {
				ext = file.getName().getExtension().toLowerCase();
				if (ext == null || ext.equals("")) {
					ext = "txt";
				}
			} else if (file.getType() == FileType.FOLDER) {
				ext = "dir";
			} else {
				ext = "txt";
			}

			String iconName = 
				iconNameMap.get(ext);
			
			if (iconName == null){//icon name wasn't found
				iconName = iconNameMap.get("txt");
			}
			iconName =  "/" +dir + "/"+ iconName ;
			
			URL url = IconFactory.class.getResource(iconName);
			if (url == null){
				throw new RuntimeException("Unable to find icon: " + iconName);
			}

			icon = new ImageIcon(url);

		} catch (FileSystemException e) {
			e.printStackTrace();
		}

		return icon;
	}

	/**
	 * This method gets an instance of an icon and uses the application
	 * resource map to cache the image. 
	 * @param file			The file whose icon you want to generate.
	 * @param resMap		The application's resource map.
	 * @param sizeConstant	The size of the icon.
	 * @return				The appropriate icon for the file or directory.
	 */
	public static Icon getInstance(FileObject file, ResourceMap resMap,
			int sizeConstant) {
		String dir = getDir(sizeConstant);

		Icon icon = null;

		try {
			String ext = null;
			if (file.getType() == FileType.FILE) {
				ext = file.getName().getExtension();
				if (ext == null || ext.equals("")) {
					ext = "txt";
				}
				ext = ext.toLowerCase();
			} else if (file.getType() == FileType.FOLDER) {
				ext = "dir";
			} else {
				ext = "txt";
			}

			String iconName = dir + "/" + iconNameMap.get(ext);
			icon = resMap.getIcon(iconName);
			

		} catch (FileSystemException e) {
			e.printStackTrace();
		}

		return icon;
	}

	/**
	 * This method gets a directory based on the icon image size.
	 * 
	 * @param sizeConstant
	 *            One of the existing image sizes. Note that not all image sizes
	 *            are supported by each icon theme.
	 * @return
	 */
	private static String getDir(int sizeConstant) {
		return "" + String.valueOf(sizeConstant) + "x"
				+ String.valueOf(sizeConstant);
	}

}
